/* 
 * File:   Interpret.h
 * Author: weeteck
 *
 * Created on 18. listopad 2012, 0:52
 */

#ifndef INTERPRET_H
#define	INTERPRET_H

#include <list>
#include <string>

class SingleCommand;

/* Seznam obsahující sekvenci příkazů. */
typedef std::list<SingleCommand*> cmdList;
/* Protisměrný iterátor seznamu příkazů. */
typedef std::list<SingleCommand*>::reverse_iterator cmdIterator;

/**
 * Třída zajišťuje provedení sekvence příkazů.
 */
class Interpret
{
public:


  /**
   * Výchozí konstruktor.
   */
  Interpret() { }


  /**
   * Výchozí destruktor.
   */
  virtual
  ~Interpret() { }


  /**
   * Funkce spouštějící interpretaci sekvence příkazů (kolony).
   * @param cmdLine Sekvence příkazů
   */
  void
  interpretCmd(cmdList & cmdLine);

  /**
   * Třída výjimky, která signalizuje chyby během interpretace sekvence příkazů.
   */
  class InterpretException
  {
  public:


    /**
     * Konstruktor výjimky.
     * @param text Nepovinný text specifikující důvod výjimky.
     */
    InterpretException(const std::string text = "") : text(text) { }


    /**
     * Výchozí destruktor.
     */
    virtual
    ~InterpretException() throw () { }


    /**
     * Vrací atribut text v podobě C-stringu.
     * @return Odkaz na C-string text.
     */
    const char*
    what() {
      return text.c_str();
    }


    /**
     * Vrací kopii atributu text.
     * @return text výjimky
     */
    std::string
    getText() {
      return text;
    }

  private:
    /** Text specifikující důvod výjimky */
    std::string text;
  };

private:


  /**
   * Rekurzivní funkce, která přímo provádí interní příkazy, nebo spouští 
   * provedení externích příkazů. Provádí se vždy ten, na který ukazuje 
   * iterátor. První se provádí poslední v sekvenci, rekurzivním voláním funkce 
   * s posunutým iterátorem se pak spouští ten v sekvenci předcházející v NOVÉM
   * PROCESU, až se dojde k prvnímu. 
   * 
   * Procesu nastavuje STDIN, STDOUT, (příp. STDERR) pro přenos mezi procesy a 
   * přsměrování ze/do souboru. 
   * Možnosti vstupu: STDIN, ze souboru, od předcházejícího příkazu (pipe).
   * Možnosti výstupu: STDOUT/STDERR, do souboru, k následujícímu příkazu (pipe).
   * 
   * @param cmdLine Sekvence příkazů
   * @param iter Iterátor nastavený na aktuální příkaz
   * @param child False = není potomkem shellu ani příkazu, True = je něčím 
   * potomkem
   */
  void
  interpretCmd(cmdList & cmdLine, cmdIterator iter, bool child);


  /**
   * Rutina která eventuelně přesměruje soubor na standardní vstup procesu - 
   * vykonávaného příkazu. Když fileName je "", neděje se nic.
   * 
   * @param fileName název souboru k přesměrování
   */
  void
  fileToStdIn(std::string fileName);


  /**
   * Rutina vytvoří rouru a nový proces, který bude vykonávat proces v 
   * sekvenci předcházející. Zajistí přesměrování deskriptorů tak, aby 
   * STDOUT nového procesu přišel (přes rouru) na STDIN aktuálního procesu. 
   * 
   * @param cmdLine celá sekvence příkazů
   * @param iter aktuální pozice iterátoru
   */
  void
  piping(cmdList & cmdLine, cmdIterator iter);


  /**
   * Rutina která eventuelně přesměruje STDOUT procesu do 
   * souboru. Jména souborů získává z objektu aktualCmd. 
   * Když některé jméno je "", neděje se nic.
   * 
   * @param aktualCmd odkaz na aktuální příkaz
   */
  void
  stdOutToFile(SingleCommand & aktualCmd);


  /**
   * Rutina která eventuelně přesměruje STDERR procesu do 
   * souboru. Jména souborů získává z objektu aktualCmd. 
   * Když některé jméno je "", neděje se nic.
   * 
   * @param aktualCmd odkaz na aktuální příkaz
   */
  void
  stdErrToFile(SingleCommand & aktualCmd);


  /**
   * Rutina která uvolní paměť po zadaném seznamu (sekvence příkazů). To by 
   * se mělo dít ve všech procesech kromě hlavního (procesu Shellu).
   * 
   * @param cmdLine odkaz na seznam příkazů
   */
  void
  destroyCmdLine(cmdList & cmdLine);


  /**
   * Funkce zjisti jestli, zadany prikaz je vestaveny prikaz shellu.
   * 
   * @param args  Nazev prikazu z prikazove radky.
   * @return true  pokud patri mezi vestavene prikazy
   *         false pokud nepatri
   */
  bool
  is_builtin_command(const char* const command);


  /**
   * Funkce provede vestavene prikazy shellu.
   * 
   * @param args  Argumenty z prikazove radky.
   * @param nargs Pocet argumentu.
   * @return 1  pokud byl proveden nektery z vestavenych prikazu
   *         0  jinak
   */
  int
  builtin_command(char** args, int nargs);


  /**
   * V aktuálním vlákně uzavře deskriptor a na jeho místo přesměruje nový. 
   * 
   * @param sourceDescr deskriptor, který bude přesměrován
   * @param destDescr deskriptor, který bude uzavřen
   */
  void
  redirectDescr(int descrToRedirect, int descrToClose);

  /**
   * Funkce zrekonstruuje retezec s prikazem, ktery byl pri analyze rozparsovan na list.
   * 
   * @param list Rozparsovany prikaz.
   * @return Retzec obsahujici puvodni prikaz.
   */
  std::string
  cmdStr(cmdList& list);

};

#endif	/* INTERPRET_H */

